The complexity of modern computer software is such that extensive testing of any new computer software is undertaken before the software can be considered to be sufficiently stable to be used, for example as a commercial product. An essential component of the software testing is the debugging of a program to identify and remove any faults in the operation of the software. One known technique applied in debugging is the use of a breakpoint. A breakpoint is the intentional stopping of a computer program for debugging purposes. This is used as a means of ascertaining information about the execution of the software, for example identifying what data is written to where in memory and so on.
A more advanced and complex use of a breakpoint is to exploit the breakpoint with a probe, or probing routine. Dynamic probing comprises a breakpoint with associated pre- and post-processing routines that may be inserted or removed from the software product's run-time code, as and when desired. To support this generalized capability a testing environment needs to interrupt the normal execution of the probed program; execute the pre-processing probe management code; single-step the probed instruction; and execute the post-processing probe management code.
Pre- and post-processing must run at the highest privilege level if they are to operate with the greatest level of flexibility in terms of data gathering. Interception of a probed instruction before and after its execution is provided though the processor architecture in the form of interrupts (sometimes purpose built debugging interrupts). This complex mechanism has been exploited by IBM's Dynamic Probes for Linux (dprobes) and other similar facilities; however, to limit complexity, the entire process from pre-processing, single-stepping and post-processing is always executed with input/output interrupts disabled. (Linux is a trademark of Linus Torvalds in the United States, other countries, or both.)
The disadvantage resulting from disabling interrupts during the entire probing process is an impact on performance: the probed instruction is replaced by a potentially long and complex series of instructions that operate as an autonomic entity. Enabling interrupts would minimise the performance impact of the probing process. However, this raises the need to solve the following problems.
First, how to preserve and restore the probe processing state while the probed instruction is being single-stepped. Where application code is probed, single-stepping potentially involves a transition from a high level of privilege (system or kernel privilege) to a low or user level for the following reason: In order to avoid compromising system integrity and security, the single-stepped instruction is executed with the privileges that would have applied under normal processing where a probe had not been inserted; Under processor architectures that afford protection mechanisms—operating system from applications and applications from each other—carefully architected mechanisms are provided such that a transition from kernel to user space and vice versa will not compromise system integrity.
One such mechanism is to disallow in general the ability of high privilege level code from calling user (or low) privilege code. Subroutine calling requires state saving such that the calling program may resume successfully; if the kernel (highest level of privilege) were to call a program in user-space (lowest level of privilege) then kernel state may have to be exposed to user-space and therefore subject unexpected alteration by a low-privilege program; but equally, user-space programs require little or no system administration or vetting to install; in a situation where the kernel calls user-space the potential for having the called program subverted or unexpectedly substituted exists.
The need to transfer control to a low privilege level from a higher level is often solved by permitting only the use of a return mechanism. This is certainly true of the IA32 architecture. RETURN, being the mechanism for completing a CALL—i.e. effecting transfer back to a caller—mandates the restoration of state and the discarding of that saved state. To use RETURN as means of “calling” user-space from the kernel requires a mechanism to be created for saving state—the opposite to that which is normally done. Because single-stepping has to be effected using a return process (for example using the IRET instruction of the IA32 architecture) it is necessary to solve the need to preserve state over a return process.
Secondly, if the probe processing state were to be preserved during the single-step, then enabling the system to be operated normally during the period over which the probed instruction is single-stepped presents the possibility for recursions through the probe management process due to probes being inserted in interrupt handling routines. Thirdly, if recursion occurs because of timer interrupts then the possibility of thread pre-emption also occurs.
The problem that is required to be solved is the ability to single-step a machine instruction (without user intervention) while allowing the processor to be enabled for interrupts, if desired, in the context of a dynamic probe point. This applies in particular to dynamic probing technologies, such as dprobes and kprobes for Linux, DTRACE for OS/2 and dtrace for Solaris and so forth. (OS/2 is a trademark of International Business Machines Corporation in the United States, other countries, or both. Solaris is a trademark of Sun Microsystems, Inc. in the United States, other countries, or both.)